#pragma once

#include "znx_atomic.h"

#define ZNX_RWLOCK_SPIN                 5
#define ZNX_RWLOCK_WLOCK                INT64_MIN

typedef struct {
    znx_atomic_int64_t      write;
    znx_atomic_int64_t      counter;
} znx_rwlock_t;

#define ZNX_RWLOCK_INITLIZER            { 0, 0 }

static inline void
znx_rwlock_init(znx_rwlock_t *lock)
{
    znx_atomic_int64_reset(&lock->write);
    znx_atomic_int64_reset(&lock->counter);
}

void znx_rwlock_wlock(znx_rwlock_t *lock);

static inline void
znx_rwlock_wunlock(znx_rwlock_t *lock)
{
    // when unlocking, it means that it has been successfully locked before.
    if (znx_atomic_int64_cas(&lock->counter, ZNX_RWLOCK_WLOCK, 0) &&
        znx_atomic_int64_cas(&lock->write, 1, 0)) {
        return;
    }

    ZNX_ASSERT_FATAL("unexpected stats");
}

void znx_rwlock_rlock(znx_rwlock_t *lock);

void znx_rwlock_runlock(znx_rwlock_t *lock);
